package com.legendframework.core.dao.transaction;

import com.legendframework.core.support.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TransactionReentrantLock extends ReentrantLock implements TransactionLock {

    private String transactionId;

    private Map<String,Integer> transactionNoCloseLockCount = new HashMap<>();

    /**
     * 设置事务ID的加锁次数
     * @param transactionId
     * @param count
     */
    private void setTransactionNoCloseLockCount(String transactionId,int count){
        transactionNoCloseLockCount.merge(transactionId, count, (a, b) -> a + b);
    }

    @Override
    public synchronized void lock(String transactionId) {
        super.lock();
        this.transactionId = transactionId;
        setTransactionNoCloseLockCount(transactionId,1);
    }

    @Override
    public synchronized boolean tryLock(String lockId) {
        if (super.tryLock()) {
            this.transactionId = lockId;
            setTransactionNoCloseLockCount(transactionId,1);
            return true;
        }
        return false;
    }

    @Override
    public boolean tryLock(String lockId, long time, TimeUnit unit) throws InterruptedException {
        if (super.tryLock(time,unit)) {
            this.transactionId = lockId;
            setTransactionNoCloseLockCount(transactionId,1);
            return true;
        }
        return false;
    }

    @Override
    public synchronized boolean unlock(String transactionId) {
        if (StringUtils.equals(transactionId, this.transactionId)) {
            super.unlock();
            this.transactionId = null;
            setTransactionNoCloseLockCount(transactionId,-1);
            Integer count = transactionNoCloseLockCount.get(transactionId);
            if (count > 0) {
                for (Integer i = 0; i < count; i++) {
                    super.unlock();
                    setTransactionNoCloseLockCount(transactionId,-1);
                }
            }
            return true;
        }
        return false;
    }
}
